﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpPcap;
using SharpPcap.Packets;
using System.Text.RegularExpressions;


namespace WC3Game
{
    public class Game
    {
        public delegate void GameStateChangeEventHandler(String msg);
        public static GameStateChangeEventHandler GameStateChanged;
        public static int Port = 6112;

        List<Team> teams = new List<Team>();

        public List<Team> Teams
        {
            get { return teams; }
            set { teams = value; }
        }


        public String Winner = String.Empty;
        public String Time
        {
            get { return String.Format("{0}:{1}", Min, Sec); }
        }

        public String Min = "0";
        public String Sec = "0";

        public Boolean Complete = false;

        public UInt64 TotalSeconds
        {
            get
            {
                UInt64 min = UInt64.Parse(Min) * 60;
                UInt64 sec = UInt64.Parse(Sec);

                return min + sec;
            }
        }

    

        public Game()
        {
            teams.Add(new Team(this, Team.TeamSide.Sentinal));
            teams.Add(new Team(this, Team.TeamSide.Scourge));
        }

        public float GetTimePercent(String time)
        {
            Regex timeRegex = new Regex(@"(\d+)h:(\d+)m:(\d+)s");
            Match match = timeRegex.Match(time);

            UInt64 currentTime = 0;

            currentTime = UInt64.Parse(match.Groups[1].Value) * 60 * 60;
            currentTime += UInt64.Parse(match.Groups[2].Value) * 60;
            currentTime += UInt64.Parse(match.Groups[3].Value);

            float percentVal = (float)currentTime / (float)TotalSeconds * 100.0f;

            return percentVal * 100.0f;
        }

        bool isStarted = false;
        SharpPcap.Packets.Util.Timeval startTime = new SharpPcap.Packets.Util.Timeval(0, 0);

        public SharpPcap.Packets.Util.Timeval StartTime
        {
            get { return startTime; }
            set { startTime = value; }
        }

        public static void SendGameStateChangeMessage(String msg)
        {
            if (GameStateChanged != null)
                GameStateChanged(msg);
        }

        public bool IsStarted
        {
            get { return isStarted; }
            set { isStarted = value; }
        }

        String name;

        public String Name
        {
            get { return name; }
            set
            {
                name = value;
                if (Session.GameCreated != null)
                    Session.GameCreated(name);
            }
        }

        String mapPath = String.Empty;

        public String MapPath
        {
            get { return mapPath; }
            set { mapPath = value; }
        }
  
        public List<Player> PlayerList
        {
            get
            {
                List<Player> tempList = new List<Player>();

                for (int i = 1; i <= 11; i++)
                {
                    if (i == 6)
                        continue;

                    Player p = PlayerFromColor(i);
                    tempList.Add(p);
                }

                return tempList;
                //return Players.Values.ToList(); 
            }
        }

        public Dictionary<Int32, Player> Players = new Dictionary<Int32, Player>();
        public List<Player> removedPlayers = new List<Player>();
        public List<GameSlot> GameSlots = new List<GameSlot>();

        public static Game CreateGame(byte[] command)
        {
            Game newGame = new Game();

            newGame.mapPath = command.ExtractString(12);
            return newGame;
        }

        public void SetGameName(byte[] command)
        {
            Name = command.ExtractString(12);
        }

        public int AddPlayer(byte[] command)
        {
            Player player = Player.CreatePlayer(command, this);

            if (Players.ContainsKey(player.ID))
            {
                if (Players[player.ID].Name == player.Name)
                {
                    Console.WriteLine("Player exists. Packet Frame: {0}", Session.FrameCounter);
                }
                else
                {
                    removedPlayers.Add(Players[player.ID]);
                    Players[player.ID] = player;
                    Console.WriteLine("ID Taken. Different Player");
                }
            }
            else
            {
                Players.Add(player.ID, player);
            }

            if (Session.PlayerAdded != null)
                Session.PlayerAdded(player.Name);

            return Players.Count;
        }

        public int AddPlayer(Player player)
        {
            Players.Add(player.ID, player);

            if (Session.PlayerAdded != null)
                Session.PlayerAdded(player.Name);

            return Players.Count;
        }

        public Player PlayerFromID(int id)
        {
            Player p =
                (from players in Players.Values
                 where players.ID == id
                 select players).SingleOrDefault();

            return p;
        }

        public Player PlayerFromColor(int slotId)
        {
            int playerId =
                (from slots in GameSlots
                 where slots.color == slotId
                 select slots.id).SingleOrDefault();

            return PlayerFromID(playerId);
        }

        public int RemovePlayer(byte[] command, SharpPcap.Packets.Util.Timeval quitTime)
        {
            short playerId = new byte[] { command[4], 0 }.ToShort();
            Player p = Players[playerId];

            if (!isStarted)
            {
#if DEBUG
                Console.WriteLine("Removing player: {0}", p.Name);
#endif

                removedPlayers.Add(p);
                Players.Remove(playerId);

                if (Session.PlayerRemoved != null)
                    Session.PlayerRemoved(p.Name);
            }
            else
            {

                // Mark the player as a leaver.
                p.Quit = true;
                p.QuitAtString = quitTime.ToTimeFormat();

                String leaveMsg = String.Format("{0} left at {1}",
                    p.Name,
                    p.QuitAtString
                    );

                if (GameStateChanged != null)
                    GameStateChanged(leaveMsg);

                if (Session.PlayerQuit != null)
                    Session.PlayerQuit(p.Name);
            }

            if (p.IsSelf)
            {
                Game.SendGameStateChangeMessage(String.Format("Game ended (incomplete) @ {0}", quitTime.ToTimeFormat()));
                Sec = quitTime.Seconds.ToString();
                Winner = "Incomplete";
                Session.AddCurrentGame();
            }

            return Players.Count;
        }
    }
    public class Team
    {
        public enum TeamSide { Sentinal, Scourge };

        public TeamSide Side;

        public Game Game;
        public List<Player> TeamPlayers
        {
            get
            {
                List<Player> teamPlayers = new List<Player>();

                int startIdx = 0;
                if (this.Side == TeamSide.Sentinal)
                {
                    startIdx = 1;
                }

                if (this.Side == TeamSide.Scourge)
                {
                    startIdx = 7;
                }

                for (int i = startIdx; i < startIdx + 5; i++)
                {
                    teamPlayers.Add(Game.PlayerFromColor(i));
                }

                return teamPlayers;
            }
        }

        public String Name
        {
            get { return Side.ToString(); }
        }

        public Team(Game game, TeamSide side)
        {
            Game = game;
            this.Side = side;
        }


    }
}
